import Axios, {AxiosPromise, AxiosRequestConfig, AxiosResponse} from 'axios'
import Qs from 'qs'
import Global from '@/config/global'
import {GetCookie, GetSession} from '@/libs/tool'

//接口返回对象结构
export interface ResponseObject {
   data: object | Array<any> | null
   code: number
   httpStatus: number
   path: string
   timestamp: number
   exception: string
}

//Response结构
export interface Response {
   status: number
}

//错误结构
export interface Error {
   response: Response
   code: number | string
   message: string
}

//Axios联合类型定义
declare type AxiosResponseType = AxiosResponse<ResponseObject | any>;
declare type AxiosResponseOnFulfilledType = AxiosPromise<Axios.Error | any> | AxiosResponseType;
declare type AxiosResponseOnRejectedType = AxiosPromise<Axios.Error | any> | void;

//api信息
const API = Global.API;
const API_LOGIN = API.login + "?fromurl=";

//错误信息的返回状态码数组
const errorArray: Array<number> = [203, 700];

//定义请求拦截
Axios.interceptors.response.use(
   (response: AxiosResponseType): AxiosResponseOnFulfilledType => {
      if (response.data.code != 0) {
         return Promise.reject({
            code: response.data.code,
            msg: response.data.exception
         });
      } else if (response.data.code == 203 || response.data.code == 700) {
         top.location.href = API_LOGIN + encodeURIComponent(self.location.href);
      }
      return Promise.resolve(response.data);
   },
   (error: Error): AxiosResponseOnRejectedType => {
      if (API.isDev) {
         console.log(error);
      }
      if (error.response) {
         if (errorArray.indexOf(error.response.status) > -1) {
            top.location.href = API_LOGIN + encodeURIComponent(self.location.href);
            return;
         }
         return Promise.reject({
            code: error.response.status,
            msg: '请求错误'
         });
      } else {
         if (error.code == 'ECONNABORTED' && error.message.indexOf('timeout') != -1) {
            return Promise.reject({
               code: -1,
               msg: '请求超时'
            });
         } else {
            return Promise.reject({
               code: -1,
               msg: '系统错误'
            });
         }
      }
   }
);

//继承原来的AxiosRequestConfig,扩展属性适应业务
interface MyAxiosRequestConfig extends AxiosRequestConfig {
   //是否强制表单提交
   form?: boolean
}

/**
 * 构造基本的Axios请求方法
 * @param userConfig 用户的axios配置
 * @param type 请求类型
 */
const baseFun = async (userConfig: MyAxiosRequestConfig = {}, type: string = "get"):Promise<any | Axios.Error> => {
   let axiosConfig = Object.assign({}, Axios.defaults, {
      baseURL: API.prefix,
      url: userConfig.url,
      method: type,
      withCredentials: true,
      timeout: 60000,
      responseType: 'json',
      validateStatus: (status: number) => {
         return status == 200;
      },
   });
   //强制请求类型为json
   axiosConfig.headers['Content-Type'] = 'application/json;charset=UTF-8';
   //用户配置覆盖内置配置
   if (userConfig.responseType) {
      axiosConfig.responseType = userConfig.responseType;
   }
   if (userConfig.headers) {
      axiosConfig.headers = Object.assign(axiosConfig.headers, userConfig.headers);
   }
   if (API.isDev) {
      let val = GetSession(Global.cacheKeyJwt);
      if (val == null && val == undefined) {
         axiosConfig.headers[Global.cacheKeyJwt] = GetCookie(Global.cacheKeyJwt);
      } else {
         axiosConfig.headers[Global.cacheKeyJwt] = GetSession(Global.cacheKeyJwt);
      }
   }
   if (userConfig.data) {
      if (type == 'get' || type == 'delete') {
         axiosConfig.params = userConfig.data;
         axiosConfig.paramsSerializer = (params) => {
            return Qs.stringify(params, {indices: false})
         };
      } else {
         axiosConfig.data = userConfig.data;
         delete axiosConfig.paramsSerializer;
         axiosConfig.transformRequest = [function (data) {
            return JSON.stringify(data);
         }]
      }
   }
   if (userConfig.form) {
      axiosConfig.headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
      axiosConfig.transformRequest = [function (data) {
         let formData = new FormData();
         let keys = Object.keys(data);
         for (let i = 0, len = keys.length; i < len; i++) {
            formData.append(keys[i], data[keys[i]])
         }
         return new URLSearchParams(formData as URLSearchParams);
      }];
   }
   return Axios(axiosConfig).then(r => {
      return r.data;
   }).catch(err => {
      if (errorArray.indexOf(err.code) > -1) {
         top.location.href = API_LOGIN + encodeURIComponent(self.location.href);
      }
      return Promise.reject(err);
   });
};

/**
 * 对应的请求类型
 */
const getFun = async (userConfig: MyAxiosRequestConfig):Promise<any | Axios.Error> => {
   return await baseFun(userConfig, 'get');
};
const postFun = async (userConfig: MyAxiosRequestConfig):Promise<any | Axios.Error> => {
   return await baseFun(userConfig, 'post');
};
const putFun = async (userConfig: MyAxiosRequestConfig):Promise<any | Axios.Error> => {
   return await baseFun(userConfig, 'put');
};
const patchFun = async (userConfig: MyAxiosRequestConfig):Promise<any | Axios.Error> => {
   return await baseFun(userConfig, 'patch');
};
const deleteFun = async (userConfig: MyAxiosRequestConfig):Promise<any | Axios.Error> => {
   return await baseFun(userConfig, 'delete');
};

//Token结构
export interface TokenConfig {
   name:string
   value:string | null
   prefix:string
}

//获取当前用户的token
const getTokenFun = ():TokenConfig => {
   let val = GetSession(Global.cacheKeyJwt);
   if (val == null && val == undefined) {
      return {
         name: Global.cacheKeyJwt,
         value: GetCookie(Global.cacheKeyJwt),
         prefix: API.prefix,
      };
   } else {
      return {
         name: Global.cacheKeyJwt,
         value: val,
         prefix: API.prefix,
      };
   }
};

//Base结构
export interface BaseConfig {
   platform:string
}

//获取基本配置
const getBaseConfig = ():BaseConfig => {
   return {
      platform: API.platform,
   }
};

export default {
   get: getFun,
   post: postFun,
   put: putFun,
   patch: patchFun,
   delete: deleteFun,
   token: getTokenFun,
   baseConfig: getBaseConfig,
}
